package main

import (
	"errors"
	"fmt"
)

/**
实现一个具有实际意义的线程池，每个任务的工作内容可以自定义，并且执行完毕之后返回相应的错误和结果，但是不能在创建线程池之后陆续添加任务
 */
func main() {
	tasks := []Task{
		{id: 0, f: func() interface{} {  fmt.Println(0); return nil }},
		{id: 1, f: func() interface{} {  fmt.Println(1); return errors.New("error1") }},
		{id: 2, f: func() interface{} { fmt.Println(2); return 1 }},
	}
	res := workPool(2, tasks)

	fmt.Printf("print err:\n %+v", res)

}

type Task struct {
	id int
	err interface{}
	f func() interface{}
}

func (t *Task) do() interface{} {
	return t.f()
}

func (t *Task) getErr() interface{} {
	return t.err
}
func createWorker(workerNum int, jobs <-chan Task, jobDone chan<- Task) {
	for i:=0; i<= workerNum; i++ {
		go func() {
			for job := range jobs {
				job.err = job.do()
				jobDone<- job
			}
		}()
	}
}

func workPool(workerNum int, tasks []Task) map[int]interface{} {
	taskNum := len(tasks)
	jobs := make(chan Task)
	jobDone := make(chan Task)
	allFinish := make(chan struct{})
	result := make(map[int]interface{})

	//创建工作线程
	createWorker(workerNum, jobs, jobDone)

	//监听工作线程是否全部完成
	go func(taskNum int, result map[int]interface{}) {
		taskDoneNum := 0
		for each := range jobDone {
			taskDoneNum++
			result[each.id] = each.err
			if taskDoneNum == taskNum {
				allFinish<-struct{}{}
				return
			}
		}
	}(taskNum, result)

	//向工作线程发送任务
	for _, task := range tasks {
		jobs<-task
	}

	//监听是否已经完成
	<-allFinish

	return result
}